<?php
/**
 * Created by PhpStorm.
 * User: bzg
 * Date: 2019/12/6
 * Time: 9:40
 */

namespace App\Extend\SysExtend\File;


use App\Common\Exception\ServiceRunTimeException;

abstract class FileAbstract
{
    protected $config;

    public function __construct($config = [])
    {
        $this->config = $config;
    }

    /**
     * 资源上传
     * @param mixed $data 文件内容 base64字符串 | 文件名 | 【base64|文件名，【验证条件】】
     * @param string $type 文件类型(file:二进制,base64:base64)
     * @param string $path 储存路径
     * @return string 服务器的相对储存路径
     * @throws ServiceRunTimeException
     */
    public function upload($data, string $type, string $path = ''): string
    {
        // TODO: Implement upload() method.
        switch (strtolower($type)) {
            case 'file':
                return $this->uploadBin($data, $path);
                break;
            case 'base64':
                return $this->uploadBase64($data, $path);
                break;
            default:
                throw new ServiceRunTimeException('不支持的文件上传方式');
        }
    }

    /**
     * 获取资源路径
     * @param string $name  文件名或者路径
     * @return string
     */
    abstract public function get(string $name) : string ;

    /**
     * 删除资源对象
     * @param string $name  文件名或者路径
     * @return bool
     */
    abstract public function delete(string $name) : bool ;

    /**
     * 上传二进制文件
     * @param string|array $file_info  文件上传信息（字符串为文件名。数组则第一元素为名字，第二元素为验证条件）
     * @param string       $path       文件上传路径
     * @return string
     * @throws ServiceRunTimeException
     */
    abstract public function uploadBin($file_info, $path);

    /**
     * 上传base64
     * @param string|array $file_info
     * @param string $path
     * @return mixed|string
     * @throws ServiceRunTimeException
     */
    abstract public function uploadBase64($file_info, $path);

    /**
     * 验证base64图片
     * @param string  $base64    base64字符串
     * @param array   $check_arr 验证条件
     *      [                               // 验证数组
     *          width => ['=',95] | 95,     // 宽px
     *          height,                     // 高px
     *          size,                       // 大小 KB
     *          ext,                        // 文件类型
     *      ]，
     * @throws ServiceRunTimeException
     * @return string  文件类型
     */
    protected function checkBase64(string $base64, array $check_arr = [])
    {

        $base64 = explode(',', self::isBase64($base64))[1];
        // 判断图片像素
        $file = base64_decode($base64);

        $img = getimagesizefromstring($file); //0:宽  1：高   3：文件格式(1,2,3,6,15)

        // base可能的图片类型
        $typeArr = [1 => 'gif', 2 => 'jpg', 3 => 'png', 6 => 'bmp'];
        // 验证条件非空
        if(!empty($check_arr)) {
            // 判断大小
            $img_len = strlen(str_replace('=', '', $base64));
            $file_size = $img_len - ($img_len / 8) * 2;
            $file_size = round(($file_size / 1024), 2);
            if (strlen($file_size) > (!empty($check_arr['size']) ? $check_arr['size'] : config('conf.upload_file.max_file_size'))) {
                throw new ServiceRunTimeException('图片过大');
            }


            if (!empty($check_arr['width'])) {
                $re = $this->checkHW($check_arr['width'],$img[0]);
                if(!$re['re'])
                    throw new ServiceRunTimeException('图片宽度应'.$re['msg'].$re['size'].'px');
            }

            if (!empty($check_arr['height'])) {
                $re = $this->checkHW($check_arr['height'],$img[1]);
                if(!$re['re'])
                    throw new ServiceRunTimeException('图片高度应'.$re['msg'].$re['size'].'px');
            }


            $allow_type = [];
            // 检查类型
            if (!empty($check_arr['ext'])) {
                $flip = array_flip($typeArr);
                foreach ($check_arr['ext'] as $v) {
                    if($v == 'jpg' || $v == 'jpeg') {
                        $allow_type[] = $flip['jpg'];
                    }else{
                        $allow_type[] = $flip[$v];
                    }
                }
            }else{
                $allow_type = $typeArr;
            }

            // 默认类型
            if (!in_array($img[2], $allow_type)) {
                throw new ServiceRunTimeException("图片格式错误");
            }
        }
        return $typeArr[$img[2]];
    }

    /**
     * 判断是否是base64文件
     * @param string $data
     * @return string
     * @throws ServiceRunTimeException
     */
    static public function isBase64(string $data)
    {
        if (!preg_match('/^(data:\s*image\/(\w+);base64,)/', $data)) {
            throw new ServiceRunTimeException("请上传base64文件");
        }
        return $data;
    }

    /**
     * 判断图片宽高大小
     * @param int|array $info 条件
     * @param int $num 实际大小
     * @return array
     */
    protected function checkHW($info,$num)
    {
        if(is_array($info)) {
            switch ($info[0]) {
                case '>':
                    return ['re' => $num > $info[0],'msg'=> '大于','size'=> $info[0]];
                case '>=':
                    return ['re' => $num >= $info[0],'msg'=> '大于等于','size'=> $info[0]];
                case '<':
                    return ['re' => $num < $info[0],'msg'=> '小于','size'=> $info[0]];
                case '<=':
                    return ['re' => $num <= $info[0],'msg'=> '小于等于','size'=> $info[0]];
                case '=':
                    return ['re' => $num == $info[0],'msg'=> '等于','size'=> $info[0]];
            }
        }else {
            return ['re' => $info == $num, 'msg' => '等于','size'=> $info];
        }
    }
}